#include "NetworkManager.h"
#include "NetworkThread.h"


// Constructor
NetworkManager::NetworkManager() {
	WSADATA wsaData;
	int iResult;

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if(iResult != 0) {
        printf("WSAStartup failed with error: %d\n", iResult);
        return;
    }

	bool bManualReset = TRUE;
	bool bInitialState = FALSE;
	this->hReady = CreateEvent(NULL, bManualReset, bInitialState, NULL);

	this->cm = new ConnectionManager(this->hReady);
}

// Deconstructor
NetworkManager::~NetworkManager() {
	delete this->cm;
}


// Allocates a new connection
Connection* NetworkManager::add() {
	return this->cm->add();
}

// Deallocates a connection
bool NetworkManager::del(Connection *conn) {
	return this->cm->del(conn);
}


// does nothing if socket is already enabled, otherwise tries to connect
bool NetworkManager::start(Connection *conn) {
//	printf("start\n");

	// check if socket is already active, return immediately if so
	if(conn->socket != NULL) {
		printf("already active\n");
		return true;
	}

	NetworkThreadStruct *nts = new NetworkThreadStruct;
	nts->nm = this;
	nts->conn = conn;
	conn->settings.set("isInit", "true");
	conn->thread = _beginthread(NetworkThread, 0, nts);

	// Wait for socket to be established before returning
	while(conn->settings.isSet("isInit")) {
//		printf("o");
	}

	return true;
}


// non-blocking check for network activity
bool NetworkManager::isReady() {
	Connection *slider;

	this->cm->reset();
	while(slider = this->cm->getNext()) {
		if(slider->settings.isSet("isNew")) {
			return true;
		}
		else if(slider->settings.isSet("isDel")) {
			return true;
		}
		else if(slider->bm->isReady()) {
			return true;
		}
	}

	return false;
}

// blocking check for network activity
void NetworkManager::waitForReady() {
	// Wait forever till signaled that network traffic is available
//	WaitForSingleObject(this->hReady, INFINITE);
	if(!WaitForSingleObject(this->hReady, 200)) {
		// Reset the isReady event to non-signaled
		ResetEvent(this->hReady);
	}
}

// one or more new connections have been established
bool NetworkManager::isNew() {
	Connection *slider;

	this->cm->reset();
	while(slider = this->cm->getNext()) {
		if(slider->settings.isSet("isNew")) {
			return true;
		}
	}

	return false;
}

// one or more existing connections have closed
bool NetworkManager::isDel() {
	Connection *slider;

	this->cm->reset();
	while(slider = this->cm->getNext()) {
		if(slider->settings.isSet("isDel")) {
			return true;
		}
	}

	return false;
}

// one or more existing connections have data
bool NetworkManager::isData() {
	Connection *slider;

	this->cm->reset();
	while(slider = this->cm->getNext()) {
		if(slider->bm->isReady()) {
			return true;
		}
	}

	return false;
}


// with each call returns a new connection & disables the new flag
Connection* NetworkManager::getNewConnection() {
	Connection *slider;

	this->cm->reset();
	while(slider = this->cm->getNext()) {
		if(slider->settings.isSet("isNew")) {
			slider->settings.del("isNew");
			return slider;
		}
	}

	return false;
}

// with each call returns a new connection & disables the new flag
Connection* NetworkManager::getDelConnection() {
	Connection *slider;

	this->cm->reset();
	while(slider = this->cm->getNext()) {
		if(slider->settings.isSet("isDel")) {
			slider->settings.del("isDel");
			return slider;
		}
	}

	return false;
}

// with each call returns a new connection & disables the new flag
Connection* NetworkManager::getDataConnection() {
	Connection *slider;

	this->cm->reset();
	while(slider = this->cm->getNext()) {
		if(slider->bm->isReady()) {
			return slider;
		}
	}

	return false;
}


// causes waitForReady to immediately return
void NetworkManager::triggerWaitForReady() {
	SetEvent(this->cm->hReady);
}


// writes to all socket connections on the specified port
void NetworkManager::write(char *data, char *value, char *bytes) {
	Connection *slider;

	this->cm->reset();
	while(slider = this->cm->getNext()) {
		if(slider->settings.isSet("isAlive")) {
			if(!strcmp(slider->settings.get(data), value)) {
				slider->write(bytes);
			}
		}
	}
}

// writes to all socket connections on the specified port
void NetworkManager::write(char *data, char *value, char *bytes, int count) {
	Connection *slider;

	this->cm->reset();
	while(slider = this->cm->getNext()) {
		if(slider->settings.isSet("isAlive")) {
			if(!strcmp(slider->settings.get(data), value)) {
				slider->write(bytes, count);
			}
		}
	}
}